package com.jxl.coreplay.managers
{
	import com.jxl.coreplay.core.IDestroy;
	import com.jxl.coreplay.core.IVideoPlayer;
	import com.jxl.coreplay.events.VideoEvent;
	import com.jxl.coreplay.net.CorePlayNetConnection;
	import com.jxl.coreplay.net.CorePlayNetStream;
	import com.jxl.coreplay.vo.StreamConfigurationVO;
	
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	import flash.geom.Rectangle;
	import flash.media.SoundTransform;
	import flash.net.NetConnection;
	import flash.utils.Timer;
	
	[Event(name="videoDurationChanged", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="streamTypeChanged", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="videoStarted", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="metadata", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="videoStopped", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="videoSeeked", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="videoResumed", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="videoPaused", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="videoCompleted", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="videoNotFound", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="bufferFull", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="bufferEmpty", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="liveDelayGood", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="liveDelayOk", type="com.jxl.coreplay.events.VideoEvent")]
	[Event(name="liveDelayBad", type="com.jxl.coreplay.events.VideoEvent")]
	
	public class AbstractStreamManager extends EventDispatcher implements IVideoPlayer, IDestroy
	{
		
		protected var _videoType:StreamConfigurationVO
		protected var _videoDuration:Number;
		protected var _volume:Number = .5;
		
		protected var corePlayNetConnection:CorePlayNetConnection;
		protected var corePlayNetStream:CorePlayNetStream;
		
		protected var lastVideoSize:Rectangle;
		protected var sizePollTimer:Timer;
		
		
		public function AbstractStreamManager(videoType:StreamConfigurationVO):void
		{
			super();
			
			_videoType = videoType;
			
			sizePollTimer = new Timer(500);
			sizePollTimer.addEventListener(TimerEvent.TIMER, onTick);
			sizePollTimer.start();
		}
		
		protected function connect(... arguments):void
		{
			destroyNetConnection();
			corePlayNetConnection = new CorePlayNetConnection(_videoType.connectionType);
			corePlayNetConnection.addEventListener(VideoEvent.CONNECT_SUCCESS, onConnectSuccess);
			var args:Array = [_videoType.rtmp];
			var params:Array = args.concat(arguments);
			corePlayNetConnection.connect.apply(corePlayNetConnection, params);
		}
		
		protected function destroyNetConnection():void
		{
			if(corePlayNetConnection != null)
			{
				corePlayNetConnection.removeEventListener(VideoEvent.CONNECT_SUCCESS, onConnectSuccess);
				corePlayNetConnection.destroy();
				corePlayNetConnection = null;
			}
		}
		
		protected function onConnectSuccess(event:VideoEvent):void
		{
		}
		
		protected function createNetStream(nc:NetConnection):void
		{
			destroyNetStream();
			
			if(corePlayNetStream == null)
			{
				corePlayNetStream = new CorePlayNetStream(corePlayNetConnection.netConnection);
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_STATE_CHANGED, 			onVideoStatusChanged);
				corePlayNetStream.addEventListener(VideoEvent.STREAM_TYPE_CHANGED,			onStreamTypeChanged);
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_STARTED,				onVideoStarted);
				corePlayNetStream.addEventListener(VideoEvent.METADATA, 					onMetaData);
				
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_STARTED, 				onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_STOPPED, 				onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_SEEKED,					onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_RESUMED, 				onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_PAUSED,					onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_COMPLETED, 				onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.VIDEO_NOT_FOUND,				onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.BUFFER_FULL, 					onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.BUFFER_EMPTY, 				onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.LIVE_DELAY_GOOD, 				onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.LIVE_DELAY_OK, 				onNetStreamStatus);
				corePlayNetStream.addEventListener(VideoEvent.LIVE_DELAY_BAD, 				onNetStreamStatus);
			}
			if(corePlayNetStream != null)
			{
				
			}
			updateNetStreamVolume();
		}
		
		protected function destroyNetStream():void
		{
			if(_videoType != null)
			{
				if(_videoType.video != null)
				{
					_videoType.video.attachNetStream(null);
				}
			}
			if(corePlayNetStream != null)
			{
				corePlayNetStream.pause();
				corePlayNetStream.close();
			}
		}
		
		
		
		protected function onVideoStatusChanged(event:VideoEvent):void
		{
			// bubble it up
			bubbleEvent(event);
		}
		
		protected function onStreamTypeChanged(event:VideoEvent):void
		{
			// bubble it up
			bubbleEvent(event);
		}
		
		protected function onVideoStarted(event:VideoEvent):void
		{
			var rect:Rectangle = _videoType.video.videoRectangle;
			lastVideoSize = rect;
		}
		
		protected function onMetaData(event:VideoEvent):void
		{
			var oldDur:Number = _videoDuration;
			_videoDuration = parseInt(corePlayNetStream.metadata.duration);
			
			var evt:VideoEvent = new VideoEvent(VideoEvent.VIDEO_DURATION_CHANGED);
			evt.oldVideoDuration = oldDur;
			evt.newVideoDuration = _videoDuration;
			dispatchEvent(evt);
			
			// bubble it up
			bubbleEvent(event);
		}
		
		protected function onNetStreamStatus(event:VideoEvent):void
		{
			// bubble it up
			bubbleEvent(event);
		}
		
		protected function bubbleEvent(event:VideoEvent):void
		{
			dispatchEvent(event);
		}
		
		protected function onTick(event:TimerEvent):void
		{
			if(_videoType != null)
			{
				if(_videoType.video != null)
				{
					var rect:Rectangle = _videoType.video.videoRectangle;
					if(lastVideoSize != null)
					{
						if(rect.width != lastVideoSize.width || rect.height != lastVideoSize.height)
						{
							// video size has changed since last measurement
							var oldRect:Rectangle 		= lastVideoSize.clone();
							lastVideoSize 			= rect;
							_videoType.video.videoSizeChanged(oldRect, lastVideoSize);
							var evt:VideoEvent = new VideoEvent(VideoEvent.VIDEO_SIZE_CHANGED);
							evt.oldVideoSize = oldRect;
							evt.newVideoSize = lastVideoSize;
							dispatchEvent(evt);
						}
					}
				}
			}
		}
		
		
		public function play():void
		{
			corePlayNetStream.play();
		}
		
		public function pause():void
		{
			corePlayNetStream.pause();
		}
		
		public function stop():void
		{
			corePlayNetStream.close();
		}
		
		public function seek(offset:Number):void
		{
			corePlayNetStream.seek(offset);
		}
		
		public function resume():void
		{
			corePlayNetStream.resume();
		}
		
		public function get volume():Number { return _volume; }
		public function set volume(val:Number):void
		{
			_volume = val;
			if(_volume > 1)
			{
				// user probably was doing it the AS2/AS1 way where volume is 1 through 100
				// coerce, and log a warning
				_volume = Math.abs(_volume / 100);
			}
			updateNetStreamVolume();
		}
		
		public function get bufferLength():Number
		{
			return corePlayNetStream.bufferLength;
		}
		
		public function get bufferTime():Number
		{
			return corePlayNetStream.bufferTime;
		}
		
		public function get bytesLoaded():Number
		{
			return corePlayNetStream.bytesLoaded;
		}
		
		public function get bytesTotal():Number
		{
			return corePlayNetStream.bytesTotal;
		}
		
		public function get duration():Number
		{
			return _videoDuration;
		}
		
		public function get time():Number
		{
			return corePlayNetStream.time;
		}
		
		public function get currentFPS():Number
		{
			return corePlayNetStream.currentFPS;
		}
		
		public function get liveDelay():Number
		{
			return corePlayNetStream.liveDelay;
		}
		
		protected function updateNetStreamVolume():void
		{
			if(corePlayNetStream != null)
			{
				var st:SoundTransform = new SoundTransform();
				st.volume = _volume;
				corePlayNetStream.soundTransform = st;
			}
		}
		
		public function destroy():void
		{
			_videoType 			= null;
			lastVideoSize 		= null;
			sizePollTimer.removeEventListener(TimerEvent.TIMER, onTick);
			sizePollTimer.stop();
			sizePollTimer 		= null;
			_videoDuration  		= -1;
			
			destroyNetStream();
			destroyNetConnection();
		}
	}
}